package plp.expressions1.expression;

import plp.expressions1.util.Tipo;

/**
 * Um objeto desta classe representa uma Expressao de Soma.
 */
public class ExpSoma extends ExpBinaria {

	/**
	 * Controi uma Expressao de Soma com as sub-expressoes especificadas.
	 * Assume-se que estas sub-expressoes resultam em <code>ValorInteiro</code> 
	 * quando avaliadas.
	 * @param esq Expressao da esquerda
	 * @param dir Expressao da direita
	 */
	public ExpSoma(Expressao esq, Expressao dir) {
		super(esq, dir, "+");
	}

	/**
	 * Retorna o valor da Expressao de Soma
	 */
	public Valor avaliar() {
		float esq = getValorExpressao(getEsq());
		float dir = getValorExpressao(getDir());		
				
		if(getTipo() == Tipo.TIPO_REAL) {
			return new ValorReal(dir + esq);
		}
		
		return new ValorInteiro((int)(dir + esq));					 
	}	

	/**
	 * Realiza a verificacao de tipos desta expressao.
	 *
	 * @return <code>true</code> se os tipos da expressao sao validos;
	 *          <code>false</code> caso contrario.
	 */
	protected boolean checaTipoElementoTerminal() {
		return (eExpressaoNumerica(getEsq()) && eExpressaoNumerica(getDir()));
	}

	/**
	 * Retorna os tipos possiveis desta expressao.
	 *
	 * @return <code>REAL</code> Caso algum dos operadores seja real.
	 * <code>INTEIRO</code>caso contrario.
	 */
	public Tipo getTipo() {
		if(getEsq().getTipo().eReal() || getDir().getTipo().eReal()) {
			return Tipo.TIPO_REAL;
		}
		
		return Tipo.TIPO_INTEIRO;
	}
	
	/*
	 * Metodo auxiliar que verifica se a expressao 
	 * contem um tipo numerico. Ou seja, se eh um real 
	 * ou inteiro.
	 */
	private boolean eExpressaoNumerica(Expressao exp) {
		return exp.getTipo().eInteiro() || exp.getTipo().eReal();
	}
	
	/*
	 * Recupera o valor da expressao. Retorna um float 
	 * independente de ser real ou inteiro.
	 */
	private float getValorExpressao(Expressao exp) {
		float valor;
		if(exp.getTipo().eReal()) {
			valor = ((ValorReal)exp.avaliar()).valor();
		}
		else {
			valor = ((ValorInteiro)exp.avaliar()).valor();
		}
		return valor;
	}

}
